/*
 * Copyright (c) 2010 by system INFORMATION TECHNOLOGY CO.
 *             All rights reserved
 */
package com.system.web.common.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @Description:
 * @Author <a href="hw86xll@163.com">Wei.Huang</a>
 * @Date 2012-10-31
 * @Version 1.0.0
 */
public class DateUtil {

	 /**
     * Number of hours in a standard day.
     */
	public static final int HOURS_PER_DAY = 24;
	 /**
     * Number of milliseconds in a standard second.
     */
    public static final long MILLIS_PER_SECOND = 1000;
    /**
     * Number of milliseconds in a standard minute.
     */
    public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
    /**
     * Number of milliseconds in a standard hour.
     */
    public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
    /**
     * Number of milliseconds in a standard day.
     */
    public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
    
    public static final String SQL_DATE_MONTH = "%Y-%m";
    public static final String SQL_DATE_DAY = "%Y-%m-%d";
    
	public enum DateTimeType {
		DateTime(0), Date(1), Time(2), Month(3), ExcelDefaultDate(4);

		private int index;

		private DateTimeType(int index) {
			this.index = index;
		}

		public int getIndex() {
			return index;
		}

		public static DateTimeType getType(int index) {
			switch (index) {
			case 1:
				return Date;
			case 2:
				return Time;
			case 3:
				return Month;
			case 4:
				return ExcelDefaultDate;
			default:
				return DateTime;
			}
		}
	}

	/**
	 * Logger for this class
	 */
	private static final Logger logger = LoggerFactory
			.getLogger(DateUtil.class);

	private static final SimpleDateFormat sdfDate = new SimpleDateFormat(
			"yyyy-MM-dd");
	private static final SimpleDateFormat sdfTime = new SimpleDateFormat(
			"HH:mm:ss");
	private static final SimpleDateFormat sdf = new SimpleDateFormat(
			"yyyy-MM-dd HH:mm:ss");

	private static final SimpleDateFormat sdfMonth = new SimpleDateFormat(
			"yyyy-MM");

	private static final SimpleDateFormat sdfExcelDefaultDate = new SimpleDateFormat(
			"yyyy/MM/dd");

	public static String format(Date date, DateTimeType type) {
		if (date == null) {
			return "";
		}
		switch (type) {
		case Date:
			return sdfDate.format(date);
		case Time:
			return sdfTime.format(date);
		case Month:
			return sdfMonth.format(date);
		case ExcelDefaultDate:
			return sdfExcelDefaultDate.format(date);
		default:
			return sdf.format(date);
		}
	}

	public static Date parse(String str, DateTimeType type) {
		if (StringUtils.isBlank(str))
			return null;
		try {
			switch (type) {
			case Date:
				return sdfDate.parse(str);
			case Time:
				return sdfTime.parse(str);
			case ExcelDefaultDate:
				return sdfExcelDefaultDate.parse(str);
			default:
				return sdf.parse(str);
			}
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}
	}

	public static Date tranDate(long time) {
		if (time == 0)
			return null;
		return new Date(time);
	}

	public static long parseDate(Date time) {
		return time == null ? 0 : time.getTime();
	}

	public static void sleepWithoutInterrupte(long time) {
		while (true) {
			try {
				Thread.sleep(time);
				break;
			} catch (InterruptedException e) {
				logger.error("Interrupted when sleep! this will be ignored!", e);
			}
		}
	}

	public static void sleepNanoWithoutInterrupte(long nanoseconds) {
		while (true) {
			try {
				TimeUnit.NANOSECONDS.sleep(nanoseconds);
				break;
			} catch (InterruptedException e) {
				logger.error("Interrupted when sleep! this will be ignored!", e);
			}
		}
	}

	public static String getCurrentDate() {
		return sdf.format(new Date());
	}

	public static String getCurrentDayBegin() {
		Calendar begin = Calendar.getInstance();
		begin.set(Calendar.HOUR_OF_DAY, 0);
		begin.set(Calendar.MINUTE, 0);
		begin.set(Calendar.SECOND, 0);
		return sdf.format(begin.getTime());
	}

	public static Date getCurDayBeginDate() {
		Calendar begin = Calendar.getInstance();
		begin.set(Calendar.HOUR_OF_DAY, 0);
		begin.set(Calendar.MINUTE, 0);
		begin.set(Calendar.SECOND, 0);
		return begin.getTime();
	}

	public static String getCurrentDayEnd() {
		Calendar end = Calendar.getInstance();
		end.set(Calendar.HOUR_OF_DAY, 23);
		end.set(Calendar.MINUTE, 59);
		end.set(Calendar.SECOND, 59);
		return sdf.format(end.getTime());
	}

	public static Date getCurDayEndDate() {
		Calendar end = Calendar.getInstance();
		end.set(Calendar.HOUR_OF_DAY, 23);
		end.set(Calendar.MINUTE, 59);
		end.set(Calendar.SECOND, 59);
		return end.getTime();
	}

	public static int getCurMonth() {
		Calendar cal = Calendar.getInstance();
		return cal.get(Calendar.MONTH) + 1;
	}

	public static String getCurMonthFirstDay() {
		Calendar begin = Calendar.getInstance();
		begin.set(Calendar.DAY_OF_MONTH, 1);
		return sdfDate.format(begin.getTime());
	}

	public static String getCurPreviousDay() {
		Calendar begin = Calendar.getInstance();
		begin.set(Calendar.DAY_OF_MONTH, begin.get(Calendar.DAY_OF_MONTH) - 1);
		return sdfDate.format(begin.getTime());
	}

	public static Date parseDate(String date) {
		try {
			if (StringUtils.isEmpty(date)) {
				return null;
			}
			return sdfDate.parse(date);
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}
	}

	public static Date parseMonth(String date) {
		try {
			if (StringUtils.isEmpty(date)) {
				return null;
			}
			return sdfMonth.parse(date);
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}
	}

	public static String getCurYearFirstMonth() {
		Calendar begin = Calendar.getInstance();
		begin.set(Calendar.MONTH, 0);
		return sdfMonth.format(begin.getTime());
	}

	public static String getCurPreviousMonth() {
		Calendar begin = Calendar.getInstance();
		int month = begin.get(Calendar.MONTH);
		if(month > 1)
			begin.set(Calendar.MONTH, begin.get(Calendar.MONTH) - 1);
		return sdfMonth.format(begin.getTime());
	}

	public static int getDays(String beginDate, String endDate) {
		try {
			Date d1 = sdfDate.parse(beginDate);
			Date d2 = sdfDate.parse(endDate);
			return (int) ((d2.getTime() - d1.getTime()) / (3600L * 1000 * 24)) + 1;
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}
	}

	public static int getMonths(String beginDate, String endDate) {

		try {
			Date d1 = sdfMonth.parse(beginDate);
			Date d2 = sdfMonth.parse(endDate);
			Calendar c1 = Calendar.getInstance();
			c1.setTime(d1);
			Calendar c2 = Calendar.getInstance();
			c2.setTime(d2);

			int beginDateYear = c1.get(Calendar.YEAR);
			int beginDateMonth = c1.get(Calendar.MONTH);
			int endDateYear = c2.get(Calendar.YEAR);
			int endDateMonth = c2.get(Calendar.MONTH);
			if (beginDateYear == endDateYear) {
				return endDateMonth - beginDateMonth + 1;
			} else {
				return (endDateYear - beginDateYear) * 12
						+ (endDateMonth - beginDateMonth) + 1;
			}
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}

	}

	public static List<String> createDate(String beginTime, String endTime) {

		List<String> dateList = new ArrayList<String>();
		try {
			Date beginDate = sdfDate.parse(beginTime);
			Date endDate = sdfDate.parse(endTime);
			Calendar beginCal = Calendar.getInstance();
			beginCal.setTime(beginDate);
			Calendar endCal = Calendar.getInstance();
			endCal.setTime(endDate);

			dateList.add(beginTime);
			dateList.add(endTime);
			if (beginTime.equals(endTime)) {
				return dateList;
			}

			int days = getDays(beginTime, endTime);
			for (int i = 0; i < days - 1; i++) {
				beginCal.add(Calendar.DAY_OF_MONTH, 1);
				Date date = beginCal.getTime();
				if (date.before(endDate)) {

					dateList.add(format(date, DateTimeType.Date));
				}
			}
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}

		return dateList;
	}

	public static List<String> createMonth(String beginMonth, String endMonth) {

		List<String> monthList = new ArrayList<String>();
		try {
			Date beginDate = sdfMonth.parse(beginMonth);
			Date endDate = sdfMonth.parse(endMonth);
			Calendar beginCal = Calendar.getInstance();
			beginCal.setTime(beginDate);
			Calendar endCal = Calendar.getInstance();
			endCal.setTime(endDate);

			monthList.add(beginMonth);
			monthList.add(endMonth);
			if (beginMonth.equals(endMonth)) {
				return monthList;
			}

			int months = getMonths(beginMonth, endMonth);
			for (int i = 0; i < months - 1; i++) {
				beginCal.add(Calendar.MONTH, 1);
				Date date = beginCal.getTime();
				if (date.before(endDate)) {

					monthList.add(format(date, DateTimeType.Month));
				}
			}
		} catch (ParseException e) {
			throw new RuntimeException("Parse date error.", e);
		}

		return monthList;
	}
}
